#ifndef GAMEENGINE_MAPS_DISPLACEMENT_H
#define GAMEENGINE_MAPS_DISPLACEMENT_H

#include <GameEngine/Maps/maps_settings.h>

#include <QtCore/QFlags>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

//=================================================================================


//! Describes a list of possible displacement types
/*!
 *  A displacement descriptor provides low-level functionnalities to manipulate
 *  which types of displacements are allowed to a given cell/terrain/unit. Four
 *  displacement types are initially described : inaccessible (i.e., the terrain
 *  is forbidden to any unit, or the unit is unable to move), walkable, swimable
 *  and flyable. Please note that some units / terrains allow a combination of
 *  these displacements. For example, crocodiles are amphibious and may either
 *  walk on the ground or swim in the river. For such case, rather than a single
 *  DisplacementType, client code can use the DisplacementTypes type which allows
 *  to combine several DisplacementType flags.
 *
 *  The DisplacementTypeCount preprocessor variable provides a convenient means to
 *  iterate over all possible types of displacement, while allowing to easily add
 *  more displacement types at a later stage. An example of code is provided below:
 *
 *  @code
 *  // Iterate over all types of displacement
 *  for ( int k = 0; k < DisplacementTypeCount; ++k ) {
 *  	// Convert index to a displacement type
 *  	Displacement::DisplacementType type = Displacement::index_to_displacement(k);
 *
 *  	// Do stuff...
 *  }
 *  @endcode
 *
 *  If you want to iterate over the types of displacement available on a specific
 *  combination of displacement types (DisplacementTypes object), please use the
 *  DisplacementTypesIterator class
 */
class _Maps_decl Displacement {

public:
	//! Enumerates which types of displacements are allowed in the given cell or to a given unit
	enum DisplacementType {
		//! No unit can access the cell
		Inaccessible = 0,
		//! Units can walk on the cell
		Walkable = 1,
		//! Units can swim on the cell
		Swimable = 2,
		//! Units can fly on the cell
		Flyable = 4
	};

	Q_DECLARE_FLAGS(DisplacementTypes,DisplacementType)

	static int displacement_to_index(DisplacementType type);
	static DisplacementType index_to_displacement(int index);
};

//! Define the number of existing displacement
#define DisplacementTypeCount 4

//========================================================

//! Iterator on the available types of a combination of displacement types
/*!
 *  In order to scan the list of displacement types available on the displacement
 *  types combination, client code should use this iterator. An example of such
 *  an iteration is given below:
 *
 *  @code
 *  DisplacementTypes types; // Should be filled with whatever appropriate displacement types
 *  for ( DisplacementTypesIterator it(types); it.more(); it.next() ) {
 *		// Get current displacement type
 *		DisplacementType current = it.cur();
 *
 *		// Do stuff...
 *  }
 *  @endcode
 *
 @note Any change in the DisplacementTypes object will invalidate all iterators using it. The
       modification may provoke incorrect type access (the current displacement type will still
	   be considered valid, even if it is no more acceptable, and all displacement types after
	   the - previously - last valid type will be ignored).
 @sa The Displacement class that handles the types of displacement themselves.
 */
class _Maps_decl DisplacementTypesIterator {

public:
	DisplacementTypesIterator(const Displacement::DisplacementTypes& types);
	DisplacementTypesIterator(const DisplacementTypesIterator& rhs);
	DisplacementTypesIterator& operator=(const DisplacementTypesIterator& rhs);
	~DisplacementTypesIterator();

	bool more() const;
	void next();
	Displacement::DisplacementType cur() const;

private:
	//! The current index of the iterator
	int index_;

	//! The maximum index of the iterator (max value included)
	int max_index_;

	//! The types of displacement associated to the iterator
	const Displacement::DisplacementTypes* types_;
};

//========================================================

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#endif
